home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
lib
/
amiga
/
profile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
7KB
|
293 lines
/*
* PROFILE.C
*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <lib/profile.h>
#include <devices/timer.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <exec/execbase.h>
/*
* force inline calls under DICE to streamline profiling. Not required
* for prevention of profiling routines getting profiled because this
* is handled with __noprof
*/
#define __DICE_INLINE
#include <clib/timer_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <stdio.h>
#include <string.h>
typedef struct CommandLineInterface CLI;
typedef struct timerequest Iot;
ProfSym *_ProfCache = 0;
ProfSym *_ProfList = 0;
ProfSym *_ProfParent = NULL;
Iot _ProfIot;
long _ProfTimeStamp;
short _ProfId = 1; /* id 0 reserved for root */
short _Prof2_0; /* running under 2.0 */
__regargs __noprof void ReadClock13(struct EClockVal *);
__regargs __noprof void
_CProfInit(ps, sysbase)
ProfSym *ps;
struct ExecBase *sysbase;
{
ps->ps_Link = _ProfList;
ps->ps_Id = _ProfId++;
_ProfList = ps;
if (sysbase->LibNode.lib_Version >= 36)
_Prof2_0 = 1;
}
/*
* Profiler call, keeps track of the amount of time a routine takes to
* run (separately for each caller of the routine). Attempts to remove
* overhead related to the profiler call itself.
*
* loops and longjumps. loops are detected when the parent is equal to
* the child while longjumps are detected when an element is not equal
* to its parent on exit.
*/
#define EVSHIFT(ev) (((ev).ev_hi << 28) | ((unsigned long)(ev).ev_lo >> 4))
#define ECBASE(n) (n >> 4)
/*#define GetEClock(evp) (_Prof2_0 ? (ReadEClock(evp), (evp)->ev_lo = EVSHIFT(*evp)) : ReadClock13(evp))*/
#define GetEClock(evp) if (_Prof2_0) {ReadEClock(evp);(evp)->ev_lo = EVSHIFT(*evp);} else {ReadClock13(evp);}
#define GetEClockBase(evp) (_Prof2_0 ? ECBASE(ReadEClock(evp)) : 62500)
static short InProf;
__regargs __noprof void
_CProfExec(id)
void *id;
{
ProfSym *ps;
short begMode;
struct EClockVal ev1;
if (InProf)
return;
++InProf;
GetEClock(&ev1);
/*
* find program symbol by Id
*/
begMode = 0;
{
ProfSym **pps = &_ProfList;
short cnt = 0;
for (ps = *pps; ps; ps = *pps) {
if (id == ps->ps_BegId) {
begMode = 1;
break;
}
if (id == ps->ps_EndId)
break;
pps = &ps->ps_Link;
++cnt;
}
if (ps && cnt > 8) { /* cache */
*pps = ps->ps_Link;
ps->ps_Link = _ProfList;
_ProfList = ps;
}
}
if (begMode) {
ProfSym *ps2;
/*
* begin new entry, close out parent entry then find new entry
* point
*/
if (ps2 = _ProfParent)
ps2->ps_AccumTime += ev1.ev_lo - ps2->ps_TimeStamp;
if (ps->ps_NumCalls == 0) {
ps->ps_Parent = ps2;
} else if (ps2 = ps) {
while (ps->ps_Parent != _ProfParent) {
if (ps->ps_SibLink) {
ps = ps->ps_SibLink;
continue;
}
if (ps->ps_SibLink = AllocMem(sizeof(ProfSym), MEMF_PUBLIC|MEMF_CLEAR)) {
ps = ps->ps_SibLink;
ps->ps_Size = sizeof(ProfSym);
ps->ps_Id = _ProfId++;
ps->ps_Parent = _ProfParent;
ps->ps_BegId = ps2->ps_BegId;
ps->ps_EndId = ps2->ps_EndId;
break;
}
}
}
/*
* if new entry point found (it had better be!) then set start
* point for entry point.
*/
if (ps) {
++ps->ps_NumCalls;
_ProfParent = ps;
ps->ps_AccumTime = 0;
GetEClock(&ev1);
ps->ps_TimeStamp = ev1.ev_lo;
}
} else if (ps = _ProfParent) {
ProfSym *ps2;
/*
* close out current entry and restart parent entry
*/
while (ps && ps->ps_EndId != id) {
ps->ps_AccumTime += ev1.ev_lo - ps->ps_TimeStamp;
ps->ps_TotalTime += ps->ps_AccumTime;
if (ps->ps_Parent)
ps->ps_Parent->ps_AccumTime += ps->ps_AccumTime;
ps->ps_AccumTime = 0;
ps = ps->ps_Parent;
}
if (ps) {
ps->ps_AccumTime += ev1.ev_lo - ps->ps_TimeStamp;
ps->ps_TotalTime += ps->ps_AccumTime;
if (_ProfParent = ps2 = ps->ps_Parent) {
ps2->ps_AccumTime += ps->ps_AccumTime;
GetEClock(&ev1);
ps2->ps_TimeStamp = ev1.ev_lo;
}
ps->ps_AccumTime = 0;
} else {
_ProfParent = ps;
}
}
--InProf;
}
__autoexit __noprof void
_CProfExit()
{
long fh;
ProfSym *ps;
ProfSym *ps2;
ProfHdr ph;
struct EClockVal ev1;
char profBuf[64];
++InProf;
profBuf[0] = 'a';
profBuf[1] = 0;
GetEClock(&ev1);
for (ps = _ProfParent; ps; ps = ps->ps_Parent) {
ps->ps_AccumTime += ev1.ev_lo - ps->ps_TimeStamp;
ps->ps_TotalTime += ps->ps_AccumTime;
if (ps->ps_Parent)
ps->ps_Parent->ps_AccumTime += ps->ps_AccumTime;
ps->ps_AccumTime = 0;
}
{
CLI *cli = (CLI *)BADDR(((struct Process *)FindTask(NULL))->pr_CLI);
if (cli) {
unsigned char *ptr = (char *)BADDR(cli->cli_CommandName);
short i, j;
for (i = *ptr; i > 0; --i) {
if (ptr[i] == ':' || ptr[i] == '/')
break;
}
for (++i, j = 0; i <= *ptr && j < sizeof(profBuf) - 8; ++i, ++j)
profBuf[j] = ptr[i];
profBuf[j] = 0;
}
}
strcat(profBuf, ".dprof");
ps = _ProfList;
_ProfList = NULL;
fh = Open(profBuf, 1006);
ph.ph_NumIds = _ProfId;
ph.ph_Magic = PROF_MAGIC;
ph.ph_TimeBase= GetEClockBase(&ev1);
Write(fh, &ph, sizeof(ph));
for (; ps; ps = ps->ps_Link) {
ProfSym *psx;
for (ps2 = ps; ps2; ps2 = psx) {
psx = ps2->ps_SibLink;
ps2->ps_SibLink = NULL;
if (ps2->ps_Parent)
ps2->ps_Parent = (void *)ps2->ps_Parent->ps_Id;
if (fh) {
if (Write(fh, ps2, ps2->ps_Size) != ps2->ps_Size) {
Close(fh);
fh = 0;
}
}
ps2->ps_Parent = NULL;
if (ps2 != ps)
FreeMem(ps2, ps2->ps_Size);
}
}
if (_ProfIot.tr_node.io_Device) {
CloseDevice(&_ProfIot.tr_node);
_ProfIot.tr_node.io_Device = NULL;
}
if (fh)
Close(fh);
}
/*
* Under 1.3 we have to use GetSysTime(), which is only accurate to
* the vertical blank (about 1/60 second). To reduce calculations and
* allow for roll-over, however, we use microsecond timing with shifts.
*
* This will glitch every 65536 seconds.
*/
__regargs __noprof void
ReadClock13(ev)
struct EClockVal *ev;
{
if (_ProfIot.tr_node.io_Device == NULL) {
OpenDevice("timer.device", UNIT_MICROHZ, &_ProfIot.tr_node, 0);
_ProfIot.tr_node.io_Command = TR_GETSYSTIME;
}
DoIO(&_ProfIot.tr_node);
ev->ev_lo = (unsigned short)_ProfIot.tr_time.tv_secs * (unsigned short)62500 + (_ProfIot.tr_time.tv_micro >> 4);
}